home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1987, 1988 Stanley T. Shebs, University of Utah. */
- /* This program may be used, copied, modified, and redistributed freely */
- /* for noncommercial purposes, so long as this notice remains intact. */
-
- #pragma comment(exestr, "@(#) curses.c 12.1 95/05/09 ")
-
- /* RCS $Header: curses.c,v 1.2 88/07/17 15:26:31 shebs Exp $ */
-
- /* Interface implementations for the curses version of xconq. */
-
- /* This file is rather simple, since there is no support for multiple */
- /* displays, no flashy graphics, and very little optimization. */
-
- #include "config.h"
- #include "misc.h"
- #include "period.h"
- #include "side.h"
- #include "map.h"
- #undef bool /* ugh */
- #include <curses.h>
-
- #ifdef UNIX
- #include <signal.h> /* needed for ^C handling */
- #endif /* UNIX */
-
- #define INFOLINES 4
-
- int helpwinlines = 1;
-
- /* Positions and sizes of the windows. */
-
- int wx[20], wy[20], ww[20], wh[20];
- int nextwin = 0; /* number of next window to open */
-
- bool alreadyopen = FALSE; /* flag to prevent double opening */
-
- /* Put in a default player, probably the invoker of the program. */
- /* Nonempty host name not actually used, but needed to keep things */
- /* straight. */
-
- add_default_player()
- {
- add_player(TRUE, "curses");
- }
-
- /* Decide what to do about ^C interrupts. */
-
- #ifdef UNIX
-
- stop_handler()
- {
- if (numhumans == 0 || Debug) {
- close_displays();
- exit(1);
- }
- }
-
- #endif /* UNIX */
-
- init_sighandlers()
- {
- #ifdef UNIX
- signal(SIGINT, stop_handler);
- #endif /* UNIX */
- }
-
- /* "Opening" a curses "display" just involves a standard sequence of calls. */
- /* Unfortunately, the "standard sequence" varies from system to system... */
-
- open_display(side)
- Side *side;
- {
- if (!alreadyopen) {
- initscr();
- nonl();
- noecho();
- #ifdef USECBREAK
- cbreak();
- #endif /* USECBREAK */
- #ifdef USECRMODE
- crmode();
- #endif /* USECRMODE */
- clear();
- side->display = 1L;
- alreadyopen = TRUE;
- return TRUE;
- } else {
- /* if we got here, we're in big trouble, so clean up quickly */
- clear();
- refresh();
- endwin();
- printf("Can't open a second display!\n");
- return FALSE;
- }
- }
-
- /* A predicate that tests whether our display can safely be written to. */
- /* This is permitted to do side-effects, although curses doesn't need */
- /* anything special. */
-
- active_display(side)
- Side *side;
- {
- return (side != NULL && side->host && !side->lost && side->display);
- }
-
- /* Display will use every character position we can get our hands on. */
-
- display_width(side) Side *side; { return COLS; }
-
- display_height(side) Side *side; { return LINES; }
-
- /* Displaying the world map usually requires a large bitmap display. */
-
- world_display(side) Side *side; { return FALSE; }
-
- /* Most sizes of things are 1 (i.e. one character cell). */
-
- init_misc(side)
- Side *side;
- {
- side->fw = side->fh = side->hh = side->hch = side->uw = side->uh = 1;
- side->hw = 2;
- side->bd = side->margin = 0;
- }
-
- /* The "root window" covers our entire display. In theory, the size of the */
- /* screen could exceed what xconq needs, but this is wildly improbable. */
-
- create_main_window(side)
- Side *side;
- {
- create_window(side, 0, 0, COLS, LINES);
- }
-
- /* Subwindow creator. */
-
- create_window(side, x, y, w, h)
- Side *side;
- int x, y, w, h;
- {
- if (x + w > COLS) w = COLS - x;
- if (y + h > LINES) h = LINES - y;
- wx[nextwin] = x; wy[nextwin] = y;
- ww[nextwin] = w; wh[nextwin] = h;
- return (nextwin++);
- }
-
- /* Help window has to be larger than most terminals allow, so blow it off. */
-
- create_help_window(side) Side *side; {}
-
- /* No special fixups to do. */
-
- fixup_windows(side) Side *side; {}
-
- enable_input(side) Side *side; {}
-
- reset_misc(side) Side *side; {}
-
- /* Moving a window just involves plugging in new values. */
-
- change_window(side, win, x, y, w, h)
- Side *side;
- int win, x, y, w, h;
- {
- if (x + w > COLS) w = COLS - x;
- if (y + h > LINES) h = LINES - y;
- if (x >= 0) {
- wx[win] = x; wy[win] = y;
- }
- if (w >= 0) {
- ww[win] = w; wh[win] = h;
- }
- }
-
- /* Actually, terminals are really "one-color", but don't take a chance on */
- /* confusing the main program. */
-
- display_colors(side) Side *side; { return 2; }
-
- white_color(side) Side *side; { return 1; }
-
- black_color(side) Side *side; { return 0; }
-
- /* Can't actually honor any color requests... */
-
- request_color(side, name) Side *side; char *name; { return 0; }
-
- /* Only kind of input is keystrokes, and from only one "display" at that. */
-
- get_input()
- {
- char ch;
- extern Side *curside;
-
- if (active_display(curside)) {
- draw_cursor(curside);
- ch = getch() & 0177;
- curside->reqtype = KEYBOARD;
- curside->reqch = ch;
- return TRUE;
- }
- }
-
- /* Wait for any input, don't care what it is. */
-
- freeze_wait(side)
- Side *side;
- {
- refresh();
- getch();
- }
-
- /* Actually would be nice to do something reasonable here. */
-
- flush_input(side) Side *side; {}
-
- /* Trivial abstraction - sometimes other routines like to ensure all output */
- /* actually on the screen. */
-
- flush_output(side) Side *side; { refresh(); }
-
- /* General window clearing. */
-
- clear_window(side, win)
- Side *side;
- int win;
- {
- int i;
-
- if (wx[win] == 0 && wy[win] == 0 && ww[win] == COLS && wh[win] == LINES) {
- clear();
- } else {
- for (i = 0; i < ww[win]; ++i) tmpbuf[i] = ' ';
- tmpbuf[ww[win]] = '\0';
- for (i = 0; i < wh[win]; ++i) mvaddstr(wy[win]+i, wx[win], tmpbuf);
- }
- }
-
- /* No world display for curses. */
-
- draw_bar(side, x, y, len, color) Side *side; int x, y, len, color; {}
-
- invert_box(side, vcx, vcy) Side *side; int vcx, vcy; {}
-
- /* This interfaces higher-level drawing decisions to the rendition of */
- /* individual pieces of display. Note that a display mode determines */
- /* whether one or two terrain characters get drawn. */
-
- draw_terrain_row(side, x, y, buf, len, color)
- Side *side;
- int x, y, len, color;
- char *buf;
- {
- int i, xi = x;
-
- for (i = 0; i < len; ++i) {
- if (xi >= wx[side->map] + ww[side->map] - 2) break;
- if (cur_at(side->map, xi, y)) {
- addch(buf[i]);
- addch((side->showmode == BORDERHEX ? ' ' : buf[i]));
- }
- xi += 2;
- }
- }
-
- /* Don't just position the cursor, but also clip and return the decision. */
-
- cur_at(win, x, y)
- int win, x, y;
- {
- if (x < 0 || x >= ww[win] || y < 0 || y >= wh[win]) {
- return FALSE;
- } else {
- move(wy[win] + y, wx[win] + x);
- return TRUE;
- }
- }
-
- /* Curses is never flashy... */
-
- flash_position(side, x, y, tm) Side *side; int x, y, tm; {}
-
- /* Curses cursor drawing is quite easy! (but ineffective? - see input fns) */
-
- draw_cursor_icon(side, x, y)
- Side *side;
- int x, y;
- {
- cur_at(side->map, x, y);
- refresh();
- }
-
- /* Doesn't seem to be necessary. */
-
- draw_hex_icon(side, win, x, y, color, ch)
- Side *side;
- int win, x, y, color;
- char ch;
- {
- }
-
- /* Splash a unit character onto some window. */
-
- draw_unit_icon(side, win, x, y, u, color)
- Side *side;
- int win;
- int x, y, u, color;
- {
- if (cur_at(win, x, y)) {
- addch(utypes[u].uchar);
- addch(' '); /* inefficient, sigh */
- }
- }
-
- /* Use the second position in a "hex" for identification of enemies. */
-
- draw_side_number(side, win, x, y, n, color)
- Side *side;
- int win, x, y, n, color;
- {
- if (cur_at(win, x+1, y)) addch((n == -1) ? '`' : n + '0');
- }
-
- /* Curses has enough trouble splatting stuff on the screen without doing */
- /* little flashes too... */
-
- draw_blast_icon(side, win, x, y, type, color)
- Side *side;
- int win, x, y, type, color;
- {
- }
-
- /* Unfortunately, terminals usually can't flash their screens. */
-
- invert_whole_map(side) Side *side; {}
-
- /* Mushroom clouds don't come out real well either. */
- /* This could be a little more elaborate. */
-
- draw_mushroom(side, x, y, i)
- Side *side;
- int x, y, i;
- {
- int sx, sy;
-
- xform(side, unwrap(side, x), y, &sx, &sy);
- if (cur_at(side->map, sx, sy)) {
- addstr("##");
- flush_output(side);
- if (i > 0) {
- if (cur_at(side->map, sx-1, sy+1)) addstr("####");
- if (cur_at(side->map, sx-2, sy)) addstr("######");
- if (cur_at(side->map, sx-1, sy-1)) addstr("####");
- flush_output(side);
- }
- }
- }
-
- /* Indicate that bar graphs are out of the question. */
-
- bar_graphs(side) Side *side; { return FALSE; }
-
- /* Thus this routine can be empty. */
-
- draw_graph(side, number, amount, total, title)
- Side *side;
- int number, amount, total;
- {
- }
-
- /* Drawing text is easy, as long as we can ignore the color of it. */
- /* Need to do manual clipping though. */
-
- draw_text(side, win, x, y, str, color)
- Side *side;
- int win;
- int x, y, color;
- char *str;
- {
- int i;
-
- if (cur_at(win, x, y)) {
- for (i = 0; i < strlen(str); ++i) {
- if (x + i >= ww[win]) return;
- addch(str[i]);
- }
- }
- }
-
- /* Can't draw lines, but this will substitute, sort of. */
-
- draw_scratchout(side, pos)
- Side *side;
- int pos;
- {
- int i;
-
- for (i = 0; i < 20; i += 2) {
- if (cur_at(side->sides, i, pos)) addch('-');
- }
- }
-
- /* Beep the beeper! */
-
- beep(side)
- Side *side;
- {
- putchar('\007');
- }
-
- /* Most help info is printable also. */
-
- reveal_help(side)
- Side *side;
- {
- notify(side, "Screen too small - writing into files instead.");
- do_printables(side, 0);
- return FALSE;
- }
-
- conceal_help(side) Side *side; {}
-
- /* Shut a single display down - presumably only called once. */
-
- close_display(side)
- Side *side;
- {
- clear();
- refresh();
- endwin();
- side->display = 0;
- }
-
- /* Completely redo a screen, making no assumptions about appearance. */
- /* This one is used frequently, especially when a window is exposed. */
-
- redraw(side)
- Side *side;
- {
- if (active_display(side)) {
- erase_cursor(side);
- clear_window(side, side->main);
- show_note(side);
- show_info(side);
- show_prompt(side);
- show_all_sides(side);
- show_timemode(side);
- show_clock(side);
- show_state(side);
- show_map(side);
- show_world(side);
- flush_output(side);
- flush_input(side);
- }
- }
-
-